home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / bin / debconf-apt-progress < prev    next >
Text File  |  2008-10-10  |  11KB  |  466 lines

  1. #!/usr/bin/perl -w
  2. # This file was preprocessed, do not edit!
  3.  
  4.  
  5. use strict;
  6. use POSIX;
  7. use Fcntl;
  8. use Getopt::Long;
  9. use Debconf::Client::ConfModule ();
  10.  
  11. my ($config, $start, $from, $to, $stop);
  12. my $progress=1;
  13. my $dlwaypoint=15;
  14. my ($logfile, $logstderr);
  15.  
  16. sub checkopen (@) {
  17.     my $file = $_[0];
  18.     my $fd = POSIX::open($file, &POSIX::O_RDONLY);
  19.     defined $fd or die "$0: can't open $_[0]: $!\n";
  20.     return $fd;
  21. }
  22.  
  23. sub checkclose ($) {
  24.     my $fd = $_[0];
  25.     unless (POSIX::close($fd)) {
  26.         return if $! == &POSIX::EBADF;
  27.         die "$0: can't close fd $fd: $!\n";
  28.     }
  29. }
  30.  
  31. sub checkdup2 ($$) {
  32.     my ($oldfd, $newfd) = @_;
  33.     checkclose($newfd);
  34.     POSIX::dup2($oldfd, $newfd)
  35.         or die "$0: can't dup fd $oldfd to $newfd: $!\n";
  36. }
  37.  
  38. sub nocloexec (*) {
  39.     my $fh = shift;
  40.     my $flags = fcntl($fh, F_GETFD, 0);
  41.     fcntl($fh, F_SETFD, $flags & ~FD_CLOEXEC);
  42. }
  43.  
  44. sub nonblock (*) {
  45.     my $fh = shift;
  46.     my $flags = fcntl($fh, F_GETFL, 0);
  47.     fcntl($fh, F_SETFL, $flags | O_NONBLOCK);
  48. }
  49.  
  50. sub reservefds (@) {
  51.     my $null = checkopen('/dev/null');
  52.     my $close = 1;
  53.     for my $fd (@_) {
  54.         if ($null == $fd) {
  55.             $close = 0;
  56.         } else {
  57.             checkclose($fd);
  58.             checkdup2($null, $fd);
  59.         }
  60.     }
  61.     if ($close) {
  62.         checkclose($null);
  63.     }
  64. }
  65.  
  66. sub envnonempty ($) {
  67.     my $name = shift;
  68.     return (exists $ENV{$name} and $ENV{$name} ne '');
  69. }
  70.  
  71. sub start_debconf (@) {
  72.     if (! $ENV{DEBIAN_HAS_FRONTEND}) {
  73.         if (envnonempty('DEBCONF_DB_REPLACE')) {
  74.             $ENV{DEBCONF_APT_PROGRESS_DB_REPLACE} =
  75.                 $ENV{DEBCONF_DB_REPLACE};
  76.         }
  77.         if (envnonempty('DEBCONF_DB_OVERRIDE')) {
  78.             $ENV{DEBCONF_APT_PROGRESS_DB_OVERRIDE} =
  79.                 $ENV{DEBCONF_DB_OVERRIDE};
  80.         }
  81.  
  82.         $ENV{DEBCONF_DB_REPLACE} = 'configdb';
  83.         $ENV{DEBCONF_DB_OVERRIDE} = 'Pipe{infd:none outfd:none}';
  84.  
  85.         @ARGV = @_;
  86.     }
  87.  
  88.     import Debconf::Client::ConfModule;
  89. }
  90.  
  91. sub passthrough (@) {
  92.     my $priority = Debconf::Client::ConfModule::get('debconf/priority');
  93.  
  94.     defined(my $pid = fork) or die "$0: can't fork: $!\n";
  95.     if (!$pid) {
  96.         close STATUS_READ;
  97.         close COMMAND_WRITE;
  98.         close DEBCONF_COMMAND_READ;
  99.         close DEBCONF_REPLY_WRITE;
  100.         $^F = 6; # avoid close-on-exec
  101.         if (fileno(COMMAND_READ) != 0) {
  102.             checkdup2(fileno(COMMAND_READ), 0);
  103.             close COMMAND_READ;
  104.         }
  105.         if (fileno(APT_LOG) != 1) {
  106.             checkclose(1);
  107.             checkdup2(fileno(APT_LOG), 1);
  108.         }
  109.         if (fileno(APT_LOG) != 2) {
  110.             checkclose(2);
  111.             checkdup2(fileno(APT_LOG), 2);
  112.         }
  113.         close APT_LOG;
  114.         delete $ENV{DEBIAN_HAS_FRONTEND};
  115.         delete $ENV{DEBCONF_REDIR};
  116.         delete $ENV{DEBCONF_SYSTEMRC};
  117.         delete $ENV{DEBCONF_PIPE}; # just in case ...
  118.         $ENV{DEBIAN_FRONTEND} = 'passthrough';
  119.         $ENV{DEBIAN_PRIORITY} = $priority;
  120.         $ENV{DEBCONF_READFD} = 5;
  121.         $ENV{DEBCONF_WRITEFD} = 6;
  122.         $ENV{APT_LISTCHANGES_FRONTEND} = 'none';
  123.         exec @_;
  124.     }
  125.  
  126.     close STATUS_WRITE;
  127.     close COMMAND_READ;
  128.     close DEBCONF_COMMAND_WRITE;
  129.     close DEBCONF_REPLY_READ;
  130.     return $pid;
  131. }
  132.  
  133. sub handle_status ($$$) {
  134.     my ($from, $to, $line) = @_;
  135.     my ($status, $pkg, $percent, $description) = split ':', $line, 4;
  136.  
  137.     my ($min, $len);
  138.     if ($status eq 'dlstatus') {
  139.         $min = 0;
  140.         $len = $dlwaypoint;
  141.     }
  142.     elsif ($status eq 'pmstatus') {
  143.         $min = $dlwaypoint;
  144.         $len = 100 - $dlwaypoint;
  145.     }
  146.     elsif ($status eq 'media-change') {
  147.         Debconf::Client::ConfModule::subst(
  148.             'debconf-apt-progress/media-change', 'MESSAGE',
  149.             $description);
  150.         my @ret = Debconf::Client::ConfModule::input(
  151.             'critical', 'debconf-apt-progress/media-change');
  152.         $ret[0] == 0 or die "Can't display media change request!\n";
  153.         Debconf::Client::ConfModule::go();
  154.         print COMMAND_WRITE "\n" || die "can't talk to command fd: $!";
  155.         return;
  156.     }
  157.     else {
  158.         return;
  159.     }
  160.  
  161.     $percent = ($percent * $len / 100 + $min);
  162.     $percent = ($percent * ($to - $from) / 100 + $from);
  163.     $percent =~ s/\..*//;
  164.     if ($progress) {
  165.         my @ret=Debconf::Client::ConfModule::progress('SET', $percent);
  166.         if ($ret[0] eq '30') {
  167.             cancel();
  168.         }
  169.     }
  170.     Debconf::Client::ConfModule::subst(
  171.         'debconf-apt-progress/info', 'DESCRIPTION', $description);
  172.     my @ret=Debconf::Client::ConfModule::progress(
  173.         'INFO', 'debconf-apt-progress/info');
  174.     if ($ret[0] eq '30') {
  175.         cancel();
  176.     }
  177. }
  178.  
  179. sub handle_debconf_command ($) {
  180.     my $line = shift;
  181.  
  182.     print "$line\n" || die "can't write to stdout: $!";
  183.     my $ret = <STDIN>;
  184.     chomp $ret;
  185.     print DEBCONF_REPLY_WRITE "$ret\n" ||
  186.         die "can't write to DEBCONF_REPLY_WRITE: $!";
  187. }
  188.  
  189. my $pid;
  190. sub run_progress ($$@) {
  191.     my $from = shift;
  192.     my $to = shift;
  193.     my $command = shift;
  194.     local (*STATUS_READ, *STATUS_WRITE);
  195.     local (*COMMAND_READ, *COMMAND_WRITE);
  196.     local (*DEBCONF_COMMAND_READ, *DEBCONF_COMMAND_WRITE);
  197.     local (*DEBCONF_REPLY_READ, *DEBCONF_REPLY_WRITE);
  198.     local *APT_LOG;
  199.     use IO::Handle;
  200.  
  201.     if ($progress) {
  202.         my @ret=Debconf::Client::ConfModule::progress(
  203.             'INFO', 'debconf-apt-progress/preparing');
  204.         if ($ret[0] eq '30') {
  205.             cancel();
  206.         }
  207.     }
  208.  
  209.     reservefds(4, 5, 6);
  210.  
  211.     pipe STATUS_READ, STATUS_WRITE
  212.         or die "$0: can't create status pipe: $!";
  213.     nonblock(\*STATUS_READ);
  214.     checkdup2(fileno(STATUS_WRITE), 4);
  215.     open STATUS_WRITE, '>&=4'
  216.         or die "$0: can't reopen STATUS_WRITE as fd 4: $!";
  217.     nocloexec(\*STATUS_WRITE);
  218.  
  219.     pipe COMMAND_READ, COMMAND_WRITE
  220.         or die "$0: can't create command pipe: $!";
  221.     nocloexec(\*COMMAND_READ);
  222.     COMMAND_WRITE->autoflush(1);
  223.  
  224.     pipe DEBCONF_COMMAND_READ, DEBCONF_COMMAND_WRITE
  225.         or die "$0: can't create debconf command pipe: $!";
  226.     nonblock(\*DEBCONF_COMMAND_READ);
  227.     checkdup2(fileno(DEBCONF_COMMAND_WRITE), 6);
  228.     open DEBCONF_COMMAND_WRITE, '>&=6'
  229.         or die "$0: can't reopen DEBCONF_COMMAND_WRITE as fd 6: $!";
  230.     nocloexec(\*DEBCONF_COMMAND_WRITE);
  231.  
  232.     pipe DEBCONF_REPLY_READ, DEBCONF_REPLY_WRITE
  233.         or die "$0: can't create debconf reply pipe: $!";
  234.     checkdup2(fileno(DEBCONF_REPLY_READ), 5);
  235.     open DEBCONF_REPLY_READ, '<&=5'
  236.         or die "$0: can't reopen DEBCONF_REPLY_READ as fd 5: $!";
  237.     nocloexec(\*DEBCONF_REPLY_READ);
  238.     DEBCONF_REPLY_WRITE->autoflush(1);
  239.  
  240.     if (defined $logfile) {
  241.         open APT_LOG, '>>', $logfile
  242.             or die "$0: can't open $logfile: $!";
  243.     } elsif ($logstderr) {
  244.         open APT_LOG, '>&STDERR'
  245.             or die "$0: can't duplicate stderr: $!";
  246.     } else {
  247.         open APT_LOG, '>', '/dev/null'
  248.             or die "$0: can't open /dev/null: $!";
  249.     }
  250.     nocloexec(\*APT_LOG);
  251.  
  252.     $pid = passthrough $command,
  253.         '-o', 'APT::Status-Fd=4',
  254.         '-o', 'APT::Keep-Fds::=5',
  255.         '-o', 'APT::Keep-Fds::=6',
  256.         @_;
  257.  
  258.     my $status_eof = 0;
  259.     my $debconf_command_eof = 0;
  260.     my $status_buf = '';
  261.     my $debconf_command_buf = '';
  262.  
  263.     while (not $status_eof) {
  264.         my $rin = '';
  265.         my $rout;
  266.         vec($rin, fileno(STATUS_READ), 1) = 1;
  267.         vec($rin, fileno(DEBCONF_COMMAND_READ), 1) = 1
  268.             unless $debconf_command_eof;
  269.         my $sel = select($rout = $rin, undef, undef, undef);
  270.         if ($sel < 0) {
  271.             next if $! == &POSIX::EINTR;
  272.             die "$0: select failed: $!";
  273.         }
  274.  
  275.         if (vec($rout, fileno(STATUS_READ), 1) == 1) {
  276.             while (1) {
  277.                 my $r = sysread(STATUS_READ, $status_buf, 4096,
  278.                         length $status_buf);
  279.                 if (not defined $r) {
  280.                     next if $! == &POSIX::EINTR;
  281.                     last if $! == &POSIX::EAGAIN or
  282.                         $! == &POSIX::EWOULDBLOCK;
  283.                     die "$0: read STATUS_READ failed: $!";
  284.                 }
  285.                 elsif ($r == 0) {
  286.                     if ($status_buf ne '' and
  287.                         $status_buf !~ /\n$/) {
  288.                         $status_buf .= "\n";
  289.                     }
  290.                     $status_eof = 1;
  291.                     last;
  292.                 }
  293.                 last if $status_buf =~ /\n/;
  294.             }
  295.  
  296.             while ($status_buf =~ /\n/) {
  297.                 my $status_line;
  298.                 ($status_line, $status_buf) =
  299.                     split /\n/, $status_buf, 2;
  300.                 handle_status $from, $to, $status_line;
  301.             }
  302.         }
  303.  
  304.         if (vec($rout, fileno(DEBCONF_COMMAND_READ), 1) == 1) {
  305.             while (1) {
  306.                 my $r = sysread(DEBCONF_COMMAND_READ,
  307.                         $debconf_command_buf, 4096,
  308.                         length $debconf_command_buf);
  309.                 if (not defined $r) {
  310.                     next if $! == &POSIX::EINTR;
  311.                     last if $! == &POSIX::EAGAIN or
  312.                         $! == &POSIX::EWOULDBLOCK;
  313.                     die "$0: read DEBCONF_COMMAND_READ " .
  314.                         "failed: $!";
  315.                 }
  316.                 elsif ($r == 0) {
  317.                     if ($debconf_command_buf ne '' and
  318.                         $debconf_command_buf !~ /\n$/) {
  319.                         $debconf_command_buf .= "\n";
  320.                     }
  321.                     $debconf_command_eof = 1;
  322.                     last;
  323.                 }
  324.                 last if $debconf_command_buf =~ /\n/;
  325.             }
  326.  
  327.             while ($debconf_command_buf =~ /\n/) {
  328.                 my $debconf_command_line;
  329.                 ($debconf_command_line, $debconf_command_buf) =
  330.                     split /\n/, $debconf_command_buf, 2;
  331.                 handle_debconf_command $debconf_command_line;
  332.             }
  333.         }
  334.     }
  335.  
  336.     waitpid $pid, 0;
  337.     my $status = $?;
  338.  
  339.     Debconf::Client::ConfModule::progress('SET', $to) if $progress;
  340.  
  341.     if ($status & 127) {
  342.         return 127;
  343.     }
  344.  
  345.     return ($status >> 8);
  346. }
  347.  
  348. my $cancelled=0;
  349. sub cancel () {
  350.     if (defined $pid) {
  351.         $cancelled++;
  352.         if ($cancelled == 1) {
  353.             kill INT => $pid;
  354.         }
  355.         else {
  356.             kill KILL => $pid;
  357.         }
  358.     }
  359. }
  360.  
  361. sub start_bar ($$) {
  362.     my ($from, $to) = @_;
  363.     if ($progress) {
  364.         Debconf::Client::ConfModule::progress(
  365.             'START', $from, $to, 'debconf-apt-progress/title');
  366.         my @ret=Debconf::Client::ConfModule::progress(
  367.             'INFO', 'debconf-apt-progress/preparing');
  368.         if ($ret[0] eq '30') {
  369.             cancel();
  370.         }
  371.     }
  372. }
  373.  
  374. sub stop_bar () {
  375.     Debconf::Client::ConfModule::progress('STOP') if $progress;
  376.     Debconf::Client::ConfModule::stop();
  377. }
  378.  
  379. if (envnonempty('DEBCONF_APT_PROGRESS_DB_REPLACE')) {
  380.     $ENV{DEBCONF_DB_REPLACE} = $ENV{DEBCONF_APT_PROGRESS_DB_REPLACE};
  381. } else {
  382.     delete $ENV{DEBCONF_DB_REPLACE};
  383. }
  384. if (envnonempty('DEBCONF_APT_PROGRESS_DB_OVERRIDE')) {
  385.     $ENV{DEBCONF_DB_OVERRIDE} = $ENV{DEBCONF_APT_PROGRESS_DB_OVERRIDE};
  386. } else {
  387.     delete $ENV{DEBCONF_DB_OVERRIDE};
  388. }
  389.  
  390. my @saved_argv = @ARGV;
  391.  
  392. my $result = GetOptions('config'       => \$config,
  393.             'start'        => \$start,
  394.             'from=i'       => \$from,
  395.             'to=i'         => \$to,
  396.             'stop'         => \$stop,
  397.             'logfile=s'    => \$logfile,
  398.             'logstderr'    => \$logstderr,
  399.             'progress!'    => \$progress,
  400.             'dlwaypoint=i' => \$dlwaypoint,
  401. );
  402.  
  403. if (! $progress && ($start || $from || $to || $stop)) {
  404.     die "--no-progress cannot be used with --start, --from, --to, or --stop\n";
  405. }
  406.  
  407. unless ($start) {
  408.     if (defined $from and not defined $to) {
  409.         die "$0: --from requires --to\n";
  410.     } elsif (defined $to and not defined $from) {
  411.         die "$0: --to requires --from\n";
  412.     }
  413. }
  414.  
  415. my $mutex = 0;
  416. ++$mutex if $config;
  417. ++$mutex if $start;
  418. ++$mutex if $stop;
  419. if ($mutex > 1) {
  420.     die "$0: must use only one of --config, --start, or --stop\n";
  421. }
  422.  
  423. if (($config or $stop) and (defined $from or defined $to)) {
  424.     die "$0: cannot use --from or --to with --config or --stop\n";
  425. }
  426.  
  427. start_debconf(@saved_argv) unless $config;
  428.  
  429. my $status = 0;
  430.  
  431. if ($config) {
  432.     print <<'EOF';
  433. DEBCONF_APT_PROGRESS_DB_REPLACE="$DEBCONF_DB_REPLACE"
  434. DEBCONF_APT_PROGRESS_DB_OVERRIDE="$DEBCONF_DB_OVERRIDE"
  435. export DEBCONF_APT_PROGRESS_DB_REPLACE DEBCONF_APT_PROGRESS_DB_OVERRIDE
  436. DEBCONF_DB_REPLACE=configdb
  437. DEBCONF_DB_OVERRIDE='Pipe{infd:none outfd:none}'
  438. export DEBCONF_DB_REPLACE DEBCONF_DB_OVERRIDE
  439. EOF
  440. } elsif ($start) {
  441.     $from = 0 unless defined $from;
  442.     $to = 100 unless defined $to;
  443.     start_bar($from, $to);
  444. } elsif (defined $from) {
  445.     $status = run_progress($from, $to, @ARGV);
  446. } elsif ($stop) {
  447.     stop_bar();
  448. } else {
  449.     start_bar(0, 100);
  450.     $status = run_progress(0, 100, @ARGV);
  451.     stop_bar();
  452. }
  453.  
  454. if ($cancelled) {
  455.     Debconf::Client::ConfModule::get("debconf/priority");
  456.  
  457.     exit 30;
  458. }
  459. elsif ($status == 30) {
  460.     exit 3;
  461. }
  462. else {
  463.     exit $status;
  464. }
  465.  
  466.